package com.demo.base.utils;

import org.springframework.util.Assert;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * Created by ethan on 2017/3/23.
 */
public abstract class HmacUtils {

    public static final String HMAC_MD5 = "HmacMD5";

    public static final String HMAC_SHA_1 = "HmacSHA1";

    public static final String HMAC_SHA_256 = "HmacSHA256";

    public static final String HMAC_SHA_384 = "HmacSHA384";

    public static final String HMAC_SHA_512 = "HmacSHA512";
    private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String hmacHex(final String algorithm, final String key, final String valueToDigest) {
        byte[] bytes = hmac(algorithm, key, valueToDigest);
        return new String(encodeHex(bytes));
    }

    public static byte[] hmac(final String algorithm, final String key, final String valueToDigest) {
        Assert.hasText(key);
        Assert.hasText(valueToDigest);
        return hmac(algorithm, key.getBytes(StandardCharsets.UTF_8), valueToDigest.getBytes(StandardCharsets.UTF_8));
    }

    public static byte[] hmac(final String algorithm, final byte[] key, final byte[] valueToDigest) {
        try {
            return getInitializedMac(algorithm, key).doFinal(valueToDigest);
        } catch (final IllegalStateException e) {
            // cannot happen
            throw new IllegalArgumentException(e);
        }
    }

    public static Mac getInitializedMac(final String algorithm, final byte[] key) {

        if (key == null) {
            throw new IllegalArgumentException("Null key");
        }

        try {
            final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
            final Mac mac = Mac.getInstance(algorithm);
            mac.init(keySpec);
            return mac;
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e);
        } catch (final InvalidKeyException e) {
            throw new IllegalArgumentException(e);
        }
    }

    private static char[] encodeHex(byte[] bytes) {
        final int l = bytes.length;
        final char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = HEX_CHARS[(0xF0 & bytes[i]) >>> 4];
            out[j++] = HEX_CHARS[0x0F & bytes[i]];
        }
        return out;

    }
}
